#include "xdebug.h"
#include "xformat.h"

#include <windows.h>

namespace xge{

  void Debug::FatalExit( const char_t* msg ) {

#ifdef XGE_USE_WIDE_CHAR

    ::FatalAppExitW( 0,
      msg
      );    

#else

    ::FatalAppExitA( 0,
      msg
      );
#endif
  }

  void Debug::Break() {

#ifdef _DEBUG
    

    // We use this __debugbreak() 
    // which is an intrinsic function 
    // namely __asm int 3
    // The ::DebugBreak won't work on my machine
    // no stacktrace dump!!!

    __debugbreak();

#endif 

  }

  void Debug::Error() {

    static const char_t* kMsg = _xT("++++++++++++Runtime Error Occur+++++++++++++!\n") \
      _xT("Get More Information From System Log: ") \
      X_SYS_LOG_FILE_NAME  ;
#ifdef _DEBUG

#ifdef XGE_USE_WIDE_CHAR
    ::OutputDebugStringW(
      kMsg
      );
#else
    ::OutputDebugStringA(
      kMsg
      );
#endif
    Break();
#else
    FatalExit( kMsg );
#endif// _Debug
  }

  // Get Last Error 

  String Debug::GetLastErrorString( int* last_error_code ) {

    DWORD temp;
    if( last_error_code ) {
      temp = GetLastError();
      *last_error_code = (int)temp;
    } else {
      last_error_code = (int*)&temp;
      temp = GetLastError();
    }

    LPVOID lpMsgBuf;

    // using format string stuff 

#ifdef XGE_USE_WIDE_CHAR

    ::FormatMessageW ( 
      FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM ,
      NULL ,
      temp ,
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      (LPTSTR)(&lpMsgBuf),
      0,
      NULL );

#else
    // This version MAKELNGID should be used
    // and should select English since only English can be displayed
    // in ansi string (c-str)
    ::FormatMessageA (
      FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM ,
      NULL ,
      temp ,
      0,
      (LPSTR)(&lpMsgBuf),
      0,
      NULL );

#endif // 

    // In order to get the named return value optimising
    struct AutoDeletor {
      AutoDeletor(void* ptr) : ptr_(ptr){}
      ~AutoDeletor() {
        LocalFree(ptr_);
      }
      void* ptr_;
    };
    AutoDeletor deletor(lpMsgBuf);
    return String((char_t*)(lpMsgBuf));

  }

  void Debug::GetLastErrorString( int* last_error_code , String* error_string ) {
    if(error_string) {
      *error_string = GetLastErrorString(last_error_code);
    }
  }

}// namespace xge
